/*
 * Copyright (c) 2011 Srdjan VESIC.
 * Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; GNU Free Documentation License is available at
http://www.gnu.org/copyleft/fdl.html
*/ 
package map;

import java.awt.BasicStroke;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Stroke;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.StringTokenizer;

/** 
 * 
 * Builds a map based on data extracted from a file
 * @author NOMS DES MEMBRES DU GROUPE
 * @version 1.0
 */
@SuppressWarnings("serial")
public class PaintMap extends Canvas  {
	
	/** The set of airports. */
	protected Hashtable<String,Airport> cities;  
	protected ArrayList<ArrayList<Airport>> neighbours;
	private ArrayList<String> airportsList = new ArrayList<String>(); 
	
	private boolean displayFlights=true;
	
	public PaintMap(Hashtable<String, Airport> aeroports) {
		cities = aeroports;

		neighbours= new ArrayList<ArrayList<Airport>>();
	}

	/** 
	 * Draws airports : circle for the position and name for each airport  
	 *  @param g Graphics containing the map
	 */
	public void paint(Graphics g) {
		Airport a;
		ArrayList<Airport> line;
		Graphics2D g2d = (Graphics2D) g;
		Stroke drawingStroke = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[]{5}, 0);
		
		// For each airport,
		java.util.Iterator<Airport> itrc = cities.values().iterator();
		while(itrc.hasNext()) {
			a = itrc.next();
			// ... draw a circle...
			g.drawOval(a.getCoord().x, a.getCoord().y, 2, 2);
			// ... and write its code. 
			g.drawString(a.getCode(), a.getCoord().x, a.getCoord().y);
		}
		
		if(!neighbours.isEmpty() && displayFlights) {
			Stroke oldStroke = g2d.getStroke();
			g2d.setStroke(drawingStroke);
			Iterator<ArrayList<Airport>> itra = neighbours.iterator();
			while(itra.hasNext()) {
				line=itra.next();
				for(int i=1;i<line.size();i++) {
					g.drawLine(line.get(0).getCoord().x, line.get(0).getCoord().y, line.get(i).getCoord().x, line.get(i).getCoord().y);
				}
			}
			g2d.setStroke(oldStroke);
		}
		g.drawRect(0, 0, 599, 599); 		// Border of the map.
		
	}

	/** Repaints the canvas given a new set of airports. (The old ones are deleted.)
	 * @param a set of airports
	 * */
	public void updateCitiesAirportList(Hashtable<String, Airport> a) {
		this.cities = a;
		updateNeighboursAirportList();
	}
	
	private void updateNeighboursAirportList() {
		if(!(cities.isEmpty())) {
   /* ******Création de la list de list d'aeroports******* */
    
		    //Pour chaque ligne de airportList
		    for(int i=0;i<airportsList.size();i++) {
		    	String neighbour;
		    	ArrayList<Airport> line = new ArrayList<Airport>();
		    	neighbours.add(line);
		    	StringTokenizer tk = new StringTokenizer(airportsList.get(i));
		    	try {
		    		//On itère sur les composants String de la ligne (tous les voisins
		    		while(true) {
		    			neighbour=tk.nextToken();
		    			//On cherche dans cities l'aeroport avec le bon code
			    				neighbours.get(i).add(cities.get(neighbour)); //Si on le trouve on l'ajoute à neighbours
		    		}
		    	} catch(Exception e) {
		    		
		    	}
		    }
		} else neighbours = new ArrayList<ArrayList<Airport>>();
	}
	
	
	/** Updates the list of airports by reading them from filename (the old airports are deleted).
	 * 
	 * @param fileName name of the file from which airports data is extracted
	 */
	public void updateCitiesFromFile(String fileName) {
		// Create a new (empty) set of airports:
		cities = new Hashtable<String, Airport>();

		try {
			// Read the file:
		    FileInputStream fstream = new FileInputStream(fileName);
		    // Get the object of DataInputStream
		    DataInputStream in = new DataInputStream(fstream);
	        BufferedReader br = new BufferedReader(new InputStreamReader(in));
		    String strLine;
		    String neighboursString; //Without coordinates
		    
		    //Read the file line by line:
		    strLine = br.readLine();
		    while (strLine != null)   {
	
		    	// If the line is empty, we hope that it is the end of the file and stop reading it.
		    	if (strLine.length() == 0) 
		    		break;
		    	
		    	
		    	
		    	// Tokenize the string.
			    StringTokenizer st = new StringTokenizer(strLine);
			    
			    // TODO: take into account possible errors. Here, we simply suppose that
			    // a string has an airport code, two integers and connections.
			    String code  = st.nextToken();
			    String x  = st.nextToken();
			    String y  = st.nextToken();
		
			    int cx = Integer.parseInt(x.trim());
		        int cy = Integer.parseInt(y.trim());
		        
		        neighboursString = code+" ";
		        try {
		        	while(true) neighboursString += st.nextToken()+ " ";
		        
		        } catch(Exception e) {
		        	
		        }
		        		        
		        airportsList.add(neighboursString);
		        
		        // We add the current airport to the list of airports. 
		        // TODO: add also the connections to an appropriate class or structure
		        // to be able to draw them later. 
		        Airport a  = new Airport(new Point(cx, cy), code);
		        cities.put(code, a);
		        	        
		        // Read the next line. 
		        strLine = br.readLine();
		    }

		    updateNeighboursAirportList();
		     
		    //Close the input stream
		    in.close();
		} catch (Exception e) {
			// TODO: handle exception
		}	
	}

	public void setDisplayFlights(boolean displayFlights) {
		this.displayFlights = displayFlights;
	}

	public boolean isDisplayFlights() {
		return displayFlights;
	}

	public Hashtable<String, Airport> getCities() {
		return cities;
	}
	
	
	
}
